// =============================================================
// CCommandLine
// ---------------------------------------
// Author : Woo-Hyun Kim
// Email : woorung@icu.ac.kr or woorung@nhncorp.com
// Date : Jul. 25, 2006
// =============================================================
#include "CCommandLine.h"

void parse_command(char * command, struct commandType *comm) {
  int i=0;
  int pos=0;
  char word[MAXLINE];

  comm->idx=0;
  comm->command=NULL;
  comm->args[0]=NULL;
  while(isspace(command[i]))
    i++; 
  if (command[i] == '\0') 
    return;
  while (command[i] != '\0') {
    while (command[i] != '\0' && !isspace(command[i])) {
      word[pos++]=command[i++];
    }
    word[pos]='\0';
    comm->args[comm->idx]=malloc((strlen(word)+1)*sizeof(char));
    strcpy(comm->args[comm->idx], word);
    comm->idx++;
    word[0]='\0';
    pos=0;
    while(isspace(command[i]))
      i++; 
  }
  comm->command=malloc((strlen(comm->args[0])+1)*sizeof(char));
  strcpy(comm->command, comm->args[0]);
  comm->args[comm->idx]=NULL;
}

CCommandLine::CCommandLine(string &cmdline)
{
	this->cmdline = cmdline;

	// create cmd_info
	cmd_info = new CCommandInfo();
}

CCommandLine::~CCommandLine()
{
	if(cmd_info!=NULL) delete cmd_info;
}

void CCommandLine::init_cmdinfo() 
{
	cmd_info->input_type = 0; // no input
	cmd_info->output_type = 0; // no output
	cmd_info->execution_type = 0; // foreground
	cmd_info->pipe_num = 0; // pipe number is 0
}

CCommandLine::parse() 
{
	char *pcmdline = cmdline.c_str();

	int pos;
	int end=0;
	char command[MAXLINE];

	if(pcmdline[i]=='\n'&&pcmdline[i]=='\0') {
		if(cmd_info!=NULL) delete cmd_info;

		cmd_info = NULL;
	}

	init_cmdinfo();

	int i = 0;
	int com_pos = 0;
	while (pcmdline[i]!='\n'&&pcmdline[i]!='\0') {
		if(pcmdline[i]=='&') { // backgroud process execution
			cmd_info->execution_type = 1;
			if (pcmdline[i+1]!='\n'&&pcmdline[i+1]!='\0') cerr << "Ignore anything beyond &" << endl;

			break;
		}
		else if (pcmdline[i] == '<') {
			cmd_info->input_type=1;
			while (isspace(pcmdline[++i]));
			pos=0;
			while (pcmdline[i] != '\0' && !isspace(pcmdline[i])) {
				if (pos==FILE_MAX_SIZE) {
  					fprintf(stderr, "Error.The input redirection file name exceeds the size limit 40\n");
  					free_info(cmd_info);
  					return NULL;
				}
				cmd_info->in_pipe[pos++] = pcmdline[i++];
			}
			cmd_info->in_pipe[pos]='\0';
			end =1;
			while (isspace(pcmdline[i])) {
				if (pcmdline[i] == '\n') break;
				i++;
			}
		}
		else if (pcmdline[i] == '>') {
			cmd_info->output_type=1;
			while (isspace(pcmdline[++i]));
			pos=0;
			while (pcmdline[i] != '\0' && !isspace(pcmdline[i])) {
				if (pos==FILE_MAX_SIZE) {
					fprintf(stderr, "Error.The output redirection file name exceeds the size limit 40\n");
					free_info(cmd_info);
					return NULL;
				}
				cmd_info->out_pipe[pos++] = pcmdline[i++];
			}
			cmd_info->out_pipe[pos]='\0';
			end =1;

			while (isspace(pcmdline[i])) {
				if (pcmdline[i] == '\n') break;
				i++;
			} 
		}
		else if (pcmdline[i] == '|') {
			command[com_pos]='\0';
			parse_command(command, &cmd_info->commands[cmd_info->pipe_num]);
			com_pos=0;
			end =0;
			cmd_info->pipe_num++;
			i++;
		}
		else {
			if (end == 1) {
				fprintf(stderr, "Error.Wrong format of input\n");
				free_info(cmd_info);
				return NULL;
			}
			if (com_pos == MAXLINE-1) {
				fprintf(stderr, "Error. The command length exceeds the limit 80\n");
				free_info(cmd_info);
				return NULL;
			}
			command[com_pos++] = pcmdline[i++];
		}
	}

	command[com_pos]='\0';
	parse_command(command, &cmd_info->commands[cmd_info->pipe_num]);
	//cmd_info->pipe_num++;
	return cmd_info;
}

void print_info (CCommandInfo *info) {
  int i, j;
  struct commandType *comm;

  if (NULL == info){
    printf("Null info\n");
    return;
  }
  printf("Parse struct:\n\n");
  printf("# of pipes:%d\n", info->pipe_num);
  for (i=0; i<=info->pipe_num;i++) {
    comm=&(info->commands[i]);
    if ((NULL == comm) || (NULL == comm->command)){
      printf("Command %d is NULL\n", i);
    } else {
      printf("Command %d is %s.\t", i+1, comm->command);
      for (j=0; j<comm->idx; j++) {
	printf("Arg %d: %s ", j, comm->args[j]);
      }
      printf("\n");
    }
  }
  printf("\n");

  if (info->input_type){
    printf("infile: %s\n", info->in_pipe);
  }else {
    printf("no input redirection.\n");
  }
  if (info->output_type) {
    printf("outfile: %s\n", info->out_pipe);
  }else {
    printf("no output redirection.\n");
  }
  if (info->execution_type){
    printf("Background process.\n");
  } else {
    printf("Foreground process.\n");
  }
}
 
void free_info (CCommandInfo *info) {
  int i,j;
  struct commandType *comm;

  if (NULL == info) return;
  for (i=0; i<PIPE_MAX_NUM;i++) {
    comm=&(info->commands[i]);
    for (j=0; j<comm->idx; j++) {
      free(comm->args[j]);
    }
    if (NULL != comm->command){
      free(comm->command);
    }
  }
  free(info);
}
